package wmhsudoku.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.JPanel;
import javax.swing.text.MaskFormatter;

import wmhsudoku.board.Map;


/**
 * @author Maciej Skrzypkowski, Sebastian Krys
 * 
 * Main panel which shows game field and current game state.
 *
 */
public class GamePanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
    private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    private GraphicsConfiguration graphicsConfiguration = ge.getDefaultScreenDevice().getDefaultConfiguration();
    private Image dbImage = null;
    private Graphics graphics;
    
    private static final String FONT = "DejaVu Sans Mono"; 
    private static final int TEXT_SCALE = 40;
    private static final int SMALL_TEXT = 21;
	private Font font = new Font(FONT, Font.BOLD, TEXT_SCALE);
	private Font smallFont = new Font(FONT, Font.BOLD, SMALL_TEXT);
	
	private MainFrame mainFrame;
	

    public GamePanel(MainFrame mainFrame) {
		super();
		setBackground(new Color(255,255,255));
		this.mainFrame = mainFrame;
		
		// if window is resized create image of new window size
		addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent e) {
				dbImage = graphicsConfiguration.createCompatibleImage(getWidth(), getHeight());
				if (dbImage == null) {
					System.out.println("dbImage is null");
					return;
				} else
					graphics = dbImage.getGraphics();
			}
		});
	}

    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
    }

    
    public void paint(Graphics g) {
    	super.paint(g);
    	paintObjects(g);
    }

    
	public void update() {
		if (dbImage == null) {
			dbImage = graphicsConfiguration.createCompatibleImage(getWidth(), getHeight());
			if (dbImage == null) {
				System.out.println("dbImage is null");
				return;
			} else
				graphics = dbImage.getGraphics();
		}
				      
        paint(graphics);
        
        drawOnScreenFromBuffer(this.getGraphics());		
	}
	
	
    private void drawOnScreenFromBuffer(Graphics g) {
        try {
          if ((g != null) && (dbImage != null))
            g.drawImage(dbImage, 0, 0, null);
          Toolkit.getDefaultToolkit().sync();  // sync the display on some systems
          g.dispose();
        }
        catch (Exception e) { 
            System.out.println("Graphics error: " + e);
        }
    }
    
    
    /**
     * Paints all objects described in physics model.
     */
    private void paintObjects(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        
    	// draw background
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        
        // draw net
        g.setColor(Color.BLACK);
        int xStep = getWidth() / mainFrame.getFieldSize();
        int yStep = getHeight() / mainFrame.getFieldSize();  
        // vertical lines
        for(int i=0; i<=mainFrame.getFieldSize(); ++i) {
        	if (i % 3 == 0) {
        	    g2.setStroke(new BasicStroke(4F));  // set stroke width of 4
        	}
        	else {
        		g2.setStroke(new BasicStroke(1F));
        	}
        	g.drawLine(i*xStep, 0, i*xStep, getHeight());
        }    
        // horizontal lines
        for(int i=0; i<=mainFrame.getFieldSize(); ++i) {
        	if (i % 3 == 0) {
        	    g2.setStroke(new BasicStroke(4F));  // set stroke width of 4
        	}
        	else {
        		g2.setStroke(new BasicStroke(1F));
        	}
        	g.drawLine(0, i*yStep, getWidth(), i*yStep);
        }     
        g2.setStroke(new BasicStroke(1F));
        
        // draw game objects:
        int textSize = TEXT_SCALE * MainFrame.DEF_FIELD_SIZE / mainFrame.getFieldSize();
        int textSizeSmall = SMALL_TEXT * MainFrame.DEF_FIELD_SIZE / mainFrame.getFieldSize();
        if (textSize > 100)
        	textSize = 100;
        if (textSizeSmall > 70)
        	textSizeSmall = 70;
        font = new Font(FONT, Font.PLAIN, textSize);
        smallFont = new Font(FONT, Font.BOLD, textSizeSmall);
    	FontRenderContext frc = g2.getFontRenderContext();
    	
    	// paint numbers
    	try {
    		Map map = mainFrame.getMap();
    		Map mask = mainFrame.getMask();
	    	if (map != null) {
	    		int grid[][] = map.getGrid();
	    		int size = map.getSize();
	    		for (int i=0; i<size; ++i) {
	    			for (int j=0; j<size; ++j) {
	    				int value = grid[j][i];
	    				if (value > 0) {
	    					if(mask.getField(i,j) == 0)
	    						g2.setColor(Color.MAGENTA);
	    					else 
	    						g2.setColor(Color.BLACK);
	    					
		    				String s = Integer.toString(value);
					    	TextLayout tl = new TextLayout(s, font, frc);
					    	tl.draw(g2, xStep*j + (int)(0.3*xStep), yStep*i + (int)(0.9*yStep));
	    				}
	    			}
	    		}
	    	} else {}
    	} catch (Exception e) {
    		System.out.println(e);
			e.printStackTrace();
		}
    	
    }

   
}
